# shooting_data <- na.omit(read.csv(file="https://github.com/chinwex/STA553/raw/main/w08/shootings.csv"))
# phil  <- na.omit(st_read("https://github.com/chinwex/STA553/raw/main/w08/shootings.geojson"))
shooting_data  <- na.omit(st_read("https://pengdsci.github.io/STA553VIZ/w08/PhillyShootings.geojson"))
phillyNeighbor  <- st_read("https://pengdsci.github.io/STA553VIZ/w08/Neighborhoods_Philadelphia.geojson")
philly  <- st_read("https://pengdsci.github.io/STA553VIZ/w08/PhillyNeighborhood-blocks.geojson")

1 Introduction

This dataset is a combination of fields from Officer Involved Shootings (OIS) data as well as fields from criminal shooting victim data from the Philadelphia Police Department. The shooting victim information is entered manually to the source database by examining investigative reports from Detectives.

There are 15277 observations and 22 variables. Some of the variables and their descriptions include:

  • AGE - The age of the individual who was shot.
  • SEX - The sex of the individual who was shot.
  • RACE - The race of the individual who was shot.
  • CODE - The Crime Classification Code based off of the FBI’s Crime Reporting (UCR) system. 0000: Additional Victim; 0100 – 0119: Homicide; 0200 – 0299: Rape; 0300 – 0399: Robbery; 0400 – 0499: Aggravated Assault; 3000 – 3900: Hospital Cases;
  • DATE - The date on which the shooting took place
  • DC_KEY - The unique incident identifier.
  • DIST - The district in which the shooting took place.
  • FATAL - Whether the individual died as a result of the shooting. 0=No and 1=Yes. The “FATAL” column is from the criminal shooting victim data and only indicates if someone died from a criminal shooting.
  • INSIDE - Whether the shooting incident took place inside a building/home, where 0=No, not inside and 1=Yes, inside.
  • LATINO - Whether or not the individual who was shot was of Latino ethnicity.
  • LOCATION - The location, generalized to the block level, of the shooting.
  • OFFENDER_DECEASED - Whether the offender died in an officer-involved shooting incident (N=No and Y=Yes).

Shown below are the first 6 observations from the dataset:

kable(head(shooting_data))
objectid year dc_key code date_ time race sex age wound officer_involved offender_injured offender_deceased location latino point_x point_y dist inside outside fatal geometry
12728033 2016 201615054780.0 400 2016-06-06 20:00:00 12:15:00 B M 19 Hand N N N 4600 BLOCK Frankford Ave 0 -75.08552 40.01489 15 0 1 0 POINT (-75.08552 40.01489)
12728034 2016 201615117555.0 300 2016-12-03 19:00:00 05:43:00 B M 38 Chest N N N 4600 BLOCK Frankford Ave 0 -75.08552 40.01489 15 0 1 0 POINT (-75.08552 40.01489)
12728035 2018 201815093657.0 400 2018-10-13 20:00:00 21:02:00 B M 31 Multiple N N N 4600 BLOCK Frankford Ave 0 -75.08552 40.01489 15 0 1 1 POINT (-75.08552 40.01489)
12728036 2020 202015094989.0 400 2020-12-01 19:00:00 17:12:00 B M 23 Hand N N N 4600 BLOCK FRANKFORD AVE 0 -75.08552 40.01489 15 0 1 0 POINT (-75.08552 40.01489)
12728037 2018 201824100255.0 400 2018-11-08 19:00:00 04:29:00 B M 27 Arm N N N 900 BLOCK E Hunting Park Ave 0 -75.10962 40.01167 24 0 1 0 POINT (-75.10962 40.01167)
12728038 2019 201924106228.0 400 2019-10-27 20:00:00 04:10:00 W M 22 Multiple N N N 900 BLOCK E HUNTING PARK AVE 1 -75.10962 40.01167 24 0 1 0 POINT (-75.10962 40.01167)

2 Objectives of the Interactive Plot

The shooting data set is neither a population nor a random sample from a population in Philadelphia. It is a set of public records of shootings in the neighborhoods of Philadelphia for the past 10 years. This data contains some geographical information such as district information, block/location, longitude, latitude etc. The main objectives are:

  • Shooting trend by year
  • Age density distribution
  • Bubble plot on the map
  • Table of total shootings categorized under Race, Sex and Age from 2015 t0 2024
  • Bar plot of shooting counts by Race
  • Map showing shooting counts for each district

2.1 Total Shootings for Districts

Shooting data was aggregated by district to include fatal, nonfatal and total shootings for all districts. This information was illustrated on a map and shown below. The circle size is proportional to the number of shootings in a district. District 25 had the largest fatal and nonfatal shootings.

shooting_data$lng = shooting_data$point_x
shooting_data$lat = shooting_data$point_y

dist.CrimeTable = table(shooting_data$fatal, shooting_data$dist)

distLon = aggregate(shooting_data$lng, by=list(shooting_data$dist), FUN=mean)
distLat = aggregate(shooting_data$lat, by=list(shooting_data$dist), FUN=mean)
distLonLat = merge(distLon, distLat, by = "Group.1")
names(distLonLat) = c("district", "lng", "lat")


distCrime = data.frame(district=as.numeric(names(table(shooting_data$dist))), 
                      fatal = table(shooting_data$fatal, shooting_data$dist)[2,],
                      nonfatal = table(shooting_data$fatal, shooting_data$dist)[1,],
                      total.crime = table(shooting_data$dist) 
                      )
distCrime = distCrime[, c("district", "fatal", "nonfatal", "total.crime.Freq")]
colnames(distCrime) = c("district", "fatal", "nonfatal", "total.crime")
distCrime = merge(distLonLat, distCrime, by = "district")

title2 <- tags$div(HTML('<font color = "darkred" size =5><b>Shootings in Philadelphia Districts</b></font>'))

pal0 <- colorNumeric(palette = viridis(256, option = "B"), domain = range(distCrime$total.crime))
distfig <- leaflet() %>%
  setView(lng=-75.1527, lat=39.9707, zoom = 11) %>%
  addProviderTiles(providers$Esri.WorldGrayCanvas) %>% 
  ## plot the neighborhood boundary of Philly
  addPolygons(data = phillyNeighbor,
              color = 'lightgreen',
              weight = 1)  %>%
   addControl(title2, position = "topright", className="map-title")%>%
  ##
  addCircleMarkers(data = distCrime,
                   radius = ~((total.crime)^(1/3)),
                   color = ~pal0(total.crime),
                   stroke = FALSE, 
                   fillOpacity = 0.5,
                   popup = ~paste('District:',district, 
                      '<br>Total Crime:', total.crime, 
                      '<br>Fatal Crime:', fatal,
                      '<br>Nonfatal Crime:', nonfatal))
distfig

A Map Showing Total Shootings in Philadelphia Districts

plot.theme <- function() {
  theme(
    plot.title = element_text(face = "bold", 
                              size = 12,
                              family = "sans", 
                              color = "#009E73",
                              hjust = 0.5),
    # add border 1)
    panel.border = element_rect(colour = "#009E73", 
                                fill = NA, 
                                linetype = 2),
    # color background 2)
   # panel.background = element_rect(fill = "#F0E442"),
    # modify grid 3)
    panel.grid.major.x = element_line(colour = "#56B4E9", 
                                      linetype = 3, 
                                      size = 0.5),
    panel.grid.minor.x = element_blank(),
    panel.grid.major.y =  element_line(colour = "#56B4E9", 
                                       linetype = 3, 
                                       size = 0.5),
    panel.grid.minor.y = element_blank(),
   
    axis.text = element_text(colour = "#56B4E9", 
                             face = "italic", 
                             family = "Times New Roman"),
    axis.title = element_text(colour = "#0072B2", 
                              family = "Times New Roman"),
    axis.ticks = element_line(colour = "#56B4E9"))
}

2.2 Shooting Trend by Year

The plot below shows the shooting trend from 2015 to 2024. There was a sharp increase in the number of shootings from 2019 to 2020. This increase was maintained all through till 2022 and then was followed by a sharp decline in 2023. The increase seen from 2020 to 2022 can be related to the coronavirus period.

# trend

yearCrime = data.frame(year=as.numeric(names(table(shooting_data$year))), 
                      fatal = table(shooting_data$fatal, shooting_data$year))

yearCrime = yearCrime[,-1]
colnames(yearCrime) = c("fatal", "year", "total")

A1 <- ggplot(data = yearCrime, aes(x = year, y = total, group = fatal, col = fatal)) +
  geom_line() +
  geom_point() +
  geom_text(aes(label = total), size = 3) +
  scale_color_manual(values=c("#D55E00", "#0072B2"), labels=c("Nonfatal", "Fatal"))+
  plot.theme()+
  labs(title = "Shooting Counts by Year",
       x = "Year",
       y = "Shooting Counts")
A1
A Trend Plot of Shooting Crimes by Year

A Trend Plot of Shooting Crimes by Year

2.3 Age Distribution

The density plot below shows the distribution of the ages of individuals who were shot. The most common age for shooting victims was 28.

## 1. age distribution
# Basic density plot in ggplot2
shooting_data$age = as.numeric(shooting_data$age)
fatalAge = ggplot(data = shooting_data, aes(x = age, fill = as.factor(fatal)) )+
           geom_density(alpha = 0.6)  +
          scale_fill_manual(values = c("#CC79A7", "#72D8FF"), labels=c("Nonfatal", "Fatal"))+
  labs(fill = "Fatal",
       title = "Distribution of Age") +
  plot.theme()
fatalAge
Age Distribution Density Plot

Age Distribution Density Plot

2.4 Race Distribution

A bar plot was used to illustrate the total shootings by race. Four different racial groups were represented in the dataset. They are Asian, Black, Unknown and White. The group with the highest number of shooting victims were Blacks with over 12000 records in 10 years.

A2 <- ggplot(data = shooting_data, aes(x = race)) +
  geom_bar(color = "#56B4E9", fill = "yellow")+
  labs(x = "Race",
       y = "Total Shootings",
       title = "Plot of Total Shootings By Race") + 
  scale_x_discrete(labels = c("A" = "Asian", "B" = "Black", "U" = "Unknown", "W" = "White")) +
  plot.theme()
A2
A Bar Plot Showing Shooting Distribution by Race

A Bar Plot Showing Shooting Distribution by Race

2.5 Summary Table

A table summarizing total shootings by sex, race, age is shown below. The average age of shooting victims was 28 in the earlier years and then increased to 31 later. Black males are more likely to be victims of shooting crimes than other groups.

dt = data.frame(year=as.numeric(names(table(shooting_data$year))), 
                      fatal = table(shooting_data$fatal, shooting_data$year)[2,],
                      nonfatal = table(shooting_data$fatal, shooting_data$year)[1,],
                      total.crime = table(shooting_data$year),
                 Black = table(shooting_data$race, shooting_data$year)[2,],
                Males = table(shooting_data$sex, shooting_data$year)[2,],
                Females = table(shooting_data$sex, shooting_data$year)[1,],
                age = signif(tapply(shooting_data$age, shooting_data$year, mean), digits = 2)
                      )
dt = dt[,-c(1,4,5)]
colnames(dt) = c("Fatal", "Nonfatal", "Black", "Males", "Females", "Age")
A3 <- DT::datatable(dt, fillContainer = FALSE, options = list(pageLength = 5))
A3

2.6 Animated Plot of Shootings By Year

which_state <- "pennsylvania"
county_info <- map_data("county", region=which_state)
philly_info <- county_info[county_info$subregion == "philadelphia",]


base_map <- ggplot(data = philly_info, mapping = aes(x = long, y = lat, group = group)) +
 geom_polygon(color = "#009E73", fill = "lightyellow") +
  coord_quickmap() +
  theme_void() 

map_with_data <- base_map +
  geom_point(data = shooting_data, aes(x = lng, y = lat, color = factor(fatal), fill = factor(fatal), group=year), size = 2, alpha = 0.5)  +
  scale_shape_manual(values = c(21, 24)) +
scale_color_manual(values = c("#0072B2", "#D55E00"))

map_with_animation <- map_with_data +
  transition_time(year) +
  ggtitle('Year: {frame_time}') +
   shadow_mark()

anim_save("ShootingsByYear.gif", map_with_animation)
map_with_animation
Animated plot of Philadelphia Shootings By Year
Animated plot of Philadelphia Shootings By Year

3 Interactive Map of Philadelphia Shootings

A map visualizing all the relevant information and key points demonstrated above is shown below.

gif = st_as_sf(data.frame(x = -75.4077, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)
tnd = st_as_sf(data.frame(x = -75.3877, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)
ageDist = st_as_sf(data.frame(x = -75.3677, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)
distloc = st_as_sf(data.frame(x = -75.3477, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)
tbl = st_as_sf(data.frame(x = -75.3277, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)
bpl = st_as_sf(data.frame(x = -75.3077, y = 39.9168),
                coords = c("x", "y"),
                crs = 4326)

title1 <- tags$div(HTML('<font color = "darkred" size =5><b>Shootings in Philadelphia</b></font>'))

fl = tempfile(fileext = ".html")
saveWidget(distfig, file = fl)


philcolor <- rep("#0072B2", length(shooting_data$fatal))
philcolor[which(shooting_data$fatal == 1)] <- "#D55E00"

shootingbyyear <- "https://github.com/chinwex/STA553/raw/main/w08/ShootingsByYear.gif"

labels <-  paste("Location: ",shooting_data$location, 
             "<br>Wound: ", shooting_data$wound,
              "<br>Sex: ", shooting_data$sex,
             "<br>Year: ", shooting_data$year,
             "<br>Age: ", shooting_data$age)%>% 
                      lapply(htmltools::HTML)


leaflet() %>%
  setView(lng=-75.15092, lat=40.00995, zoom = 11) %>%
  #addProviderTiles(providers$Esri.WorldGrayCanvas, group = "Grey")%>%
  addProviderTiles(providers$CartoDB.DarkMatter, group="Dark") %>%
  addProviderTiles(providers$CartoDB.DarkMatterNoLabels, group="DarkLabel") %>%  
 addProviderTiles(providers$Esri.NatGeoWorldMap, group="Esri") %>%
  
  addControl(title1, position = "topright", className="map-title") %>%
  ## mini reference map
  addMiniMap() %>%
  ## neighborhood boundary
  addPolygons(data = phillyNeighbor,
              color = 'lightgreen',
              weight = 1)  %>%
  ## plot information on the map
  addCircleMarkers(data = shooting_data,
                     ~lng, 
                     ~lat,
            color = philcolor,
            fillColor = ifelse(shooting_data$fatal == 1, "#ffff66", "#ff99ff"),
            radius = 10,
            opacity = 1,
           # stroke = FALSE, 
           fillOpacity = 0.25,
            label = ~labels,
            clusterOptions = markerClusterOptions(maxClusterRadius = 40)) %>%
  
  # Trend of crimes over the years
  addCircleMarkers(data = tnd, 
                   color = "red",
                   weight = 2,
                   label = "Trend",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "tnd") %>%
  addPopupGraphs(list(A1), 
                  width = 450,
                  height = 300,
                  tooltip = FALSE,
                  group = "tnd") %>%
 # age distribution within the two types of crimes
 addCircleMarkers(data = ageDist, 
                   color = "#0072B2",
                   weight = 2,
                   label = "Age Distribution",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "ageDist") %>%
  addPopupGraphs(list(fatalAge), 
                  width = 450,
                  height = 300,
                  tooltip = FALSE,
                  group = "ageDist") %>%
  # shooting counts by district: bubble plot
  addCircleMarkers(data = distloc, 
                   color = "purple",
                   weight = 2,
                   label = "Crimes by District",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "distloc") %>%
  leafpop:::addPopupIframes(
                  source = fl,
                   width = 450,
                  height = 300,
                   group = "distloc") %>%
  # Animated shooting counts by years
   addCircleMarkers(data = gif, 
                   color = "#CC79A7",
                   weight = 2,
                   label = "Shootings by year",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "gif") %>%
  addPopupImages(shootingbyyear, 
                  width = 450,
                  height = 300,
                  tooltip = FALSE,
                  group = "gif") %>% 
  addCircleMarkers(data = tbl, 
                   color = "gold",
                   weight = 2,
                   label = "Summary Table",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "tbl",
                   popup = htmlTable(dt)) %>%
  # barplot of crime by race
  addCircleMarkers(data = bpl, 
                   color = "green",
                   weight = 2,
                   label = "Crime by Race",
                   stroke = FALSE, 
                   fillOpacity = 0.95,
                   group = "bpl") %>%
  addPopupGraphs(list(A2), 
                  width = 450,
                  height = 300,
                  tooltip = FALSE,
                  group = "bpl") %>%
  addLayersControl(baseGroups = c('Dark', 'DarkLabel', 'Esri'),
                   overlayGroups = c("Shooting Data"),
                   options = layersControlOptions(collapsed = TRUE)) %>%
  ##
  browsable()

A Map of Philadelphia Shootings

LS0tDQp0aXRsZTogIlZpc3VhbGl6aW5nIEdlb3NwYXRpYWwgSW5mb3JtYXRpb24gLSBBIENhc2UgU3R1ZHkiDQphdXRob3I6ICJFY2hlZnUgQ2hpbndlbmR1Ig0KZGF0ZTogIjIwMjQtMDMtMjciDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBmaWdfd2lkdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgZmlnX2hlaWdodDogNA0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoNCi8qIFRhYmxlIG9mIGNvbnRlbnQgLSBuYXZpZ2F0aW9uICovDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1jb2xvcjpsaWdodGdyYXk7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGNvbG9yOiAjNzgwYzBjOw0KfQ0KDQoNCi8qIFRpdGxlIGZvbnRzICovDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IGRhcmtibHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQpoNC5kYXRlIHsgDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC1mYW1pbHk6IEFyaWFsLCBIZWx2ZXRpY2EsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBkYXJrYmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQovKiBTZWN0aW9uIGhlYWRlcnMgKi8NCmgxIHsNCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDIgew0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IA0KICAgIGZvbnQtc2l6ZTogMTVweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7DQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIERlY29yYXRpb24gb2YgaHlwZXJsaW5rcyAgKi8NCg0KLyogdW52aXNpdGVkIGxpbmsgKi8NCmE6bGluayB7DQogIGNvbG9yOiBncmVlbjsNCn0NCg0KLyogdmlzaXRlZCBsaW5rICovDQphOnZpc2l0ZWQgew0KICBjb2xvcjogcHVycGxlOw0KfQ0KDQovKiBtb3VzZSBvdmVyIGxpbmsgKi8NCmE6aG92ZXIgew0KICBjb2xvcjogcmVkOw0KfQ0KDQovKiBzZWxlY3RlZCBsaW5rICovDQphOmFjdGl2ZSB7DQogIGNvbG9yOiB5ZWxsb3c7DQp9DQo8L3N0eWxlPg0KYGBgDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCm9wdGlvbnMocmVwb3MgPSBsaXN0KENSQU49Imh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpKQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb3dwbG90IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQ0KICAgbGlicmFyeShjb3dwbG90KQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXRleDJleHAiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGF0ZXgyZXhwIikNCiAgIGxpYnJhcnkobGF0ZXgyZXhwKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgIGxpYnJhcnkocGxvdGx5KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnYXBtaW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCiAgIGxpYnJhcnkoZ2FwbWluZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbmciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBuZyIpICAgICAgICAgICAgICMgSW5zdGFsbCBwbmcgcGFja2FnZQ0KICAgIGxpYnJhcnkoInBuZyIpDQp9DQppZiAoIXJlcXVpcmUoIlJDdXJsIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpICAgICAgICAgICAgICMgSW5zdGFsbCBSQ3VybCBwYWNrYWdlDQogICAgbGlicmFyeSgiUkN1cmwiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb2xvdXJwaWNrZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNvbG91cnBpY2tlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjb2xvdXJwaWNrZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ2FuaW1hdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnYW5pbWF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2FuaW1hdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnaWZza2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdpZnNraSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnaWZza2kiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYWdpY2siKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJtYWdpY2siKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnckRldmljZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdyRGV2aWNlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnckRldmljZXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJqcGVnIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJqcGVnIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImpwZWciKQ0KfQ0KaWYgKCFyZXF1aXJlKCJWR0FNIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIlZHQU0iKQ0KfQ0KaWYgKCFyZXF1aXJlKCJNQVNTIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIk1BU1MiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJubmV0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJubmV0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIm5uZXQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjbHVzdGVyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjbHVzdGVyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImNsdXN0ZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJzdHJpbmdyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInN0cmluZ3IiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShzdHJpbmdyKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInRtIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRtIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgIGxpYnJhcnkodG0pDQp9DQoNCmlmICghcmVxdWlyZSgid29yZGNsb3VkIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIndvcmRjbG91ZCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KHdvcmRjbG91ZCkNCn0NCg0KaWYgKCFyZXF1aXJlKCJSQ3VybCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogICBsaWJyYXJ5KFJDdXJsKQ0KfQ0KDQppZiAoIXJlcXVpcmUoIlhNTCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJYTUwiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShYTUwpDQp9DQppZiAoIXJlcXVpcmUoIlNub3diYWxsQyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJTbm93YmFsbEMiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShTbm93YmFsbEMpDQp9DQppZiAoIXJlcXVpcmUoIlJDb2xvckJyZXdlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICAgbGlicmFyeShSQ29sb3JCcmV3ZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dwbG90MiIpDQp9DQppZiAoIXJlcXVpcmUoImdnYW5pbWF0ZSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dhbmltYXRlIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdnYW5pbWF0ZSIpDQp9DQppZiAoIXJlcXVpcmUoImdyYXBoaWNzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJncmFwaGljcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJncmFwaGljcyIpDQp9DQppZiAoIXJlcXVpcmUoImdncmlkZ2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ3JpZGdlcyIpDQp9DQppZiAoIXJlcXVpcmUoInBseXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBseXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgicGx5ciIpDQp9DQppZiAoIXJlcXVpcmUoImdnaXJhcGgiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdnaXJhcGgiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dpcmFwaCIpDQp9DQppZiAoIXJlcXVpcmUoImhpZ2hjaGFydGVyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJoaWdoY2hhcnRlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJoaWdoY2hhcnRlciIpDQp9DQppZiAoIXJlcXVpcmUoImZvcmVjYXN0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJmb3JlY2FzdCIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZsZXQiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZmxldCIpDQp9DQppZiAoIXJlcXVpcmUoIm1hcHMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hcHMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFwcyIpDQp9DQppZiAoIXJlcXVpcmUoImh0bWx0b29scyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiaHRtbHRvb2xzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImh0bWx0b29scyIpDQp9DQppZiAoIXJlcXVpcmUoImh0bWx3aWRnZXRzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJodG1sd2lkZ2V0cyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJodG1sd2lkZ2V0cyIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZsZWdlbmQiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZsZWdlbmQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZmxlZ2VuZCIpDQp9DQppZiAoIXJlcXVpcmUoImdlb2pzb25pbyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2VvanNvbmlvIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdlb2pzb25pbyIpDQp9DQppZiAoIXJlcXVpcmUoInN0cmluZ2kiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInN0cmluZ2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgic3RyaW5naSIpDQp9DQppZiAoIXJlcXVpcmUoIlJDb2xvckJyZXdlciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiUkNvbG9yQnJld2VyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIlJDb2xvckJyZXdlciIpDQp9DQppZiAoIXJlcXVpcmUoInRpZ3JpcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygidGlncmlzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInRpZ3JpcyIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZwb3AiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZwb3AiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZnBvcCIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZlbSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmVtIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZlbSIpDQp9DQppZiAoIXJlcXVpcmUoInRtYXAiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInRtYXAiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgidG1hcCIpDQp9DQppZiAoIXJlcXVpcmUoInRtYXB0b29scyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygidG1hcHRvb2xzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInRtYXB0b29scyIpDQp9DQppZiAoIXJlcXVpcmUoIndlYnNob3QyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ3ZWJzaG90MiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJ3ZWJzaG90MiIpDQp9DQppZiAoIXJlcXVpcmUoInNmIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJzZiIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJzZiIpDQp9DQppZiAoIXJlcXVpcmUoInRlcnJhIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ0ZXJyYSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJ0ZXJyYSIpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZwb3AiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImxlYWZwb3AiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibGVhZnBvcCIpDQp9DQppZiAoIXJlcXVpcmUoIm1hcHZpZXciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoIm1hcHZpZXciKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFwdmlldyIpDQp9DQppZiAoIXJlcXVpcmUoInNwRGF0YSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic3BEYXRhIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInNwRGF0YSIpDQp9DQppZighcmVxdWlyZSgiYW5pbWF0aW9uIikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJhbmltYXRpb24iKQ0KICBsaWJyYXJ5KGFuaW1hdGlvbikNCn0NCmlmKCFyZXF1aXJlKCJnZ21hcCIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dtYXAiKQ0KICBsaWJyYXJ5KGdnbWFwKQ0KfQ0KaWYoIXJlcXVpcmUoImh0bWxUYWJsZSIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygiaHRtbFRhYmxlIikNCiAgbGlicmFyeShodG1sVGFibGUpDQp9DQppZighcmVxdWlyZSgibWFncml0dHIiKSl7DQogIGluc3RhbGwucGFja2FnZXMoIm1hZ3JpdHRyIikNCiAgbGlicmFyeShtYWdyaXR0cikNCn0NCmlmKCFyZXF1aXJlKCJ3ZWJzaG90Iikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ3ZWJzaG90IikNCiAgbGlicmFyeSh3ZWJzaG90KQ0KfQ0KaWYoIXJlcXVpcmUoInZpcmlkaXMiKSl7DQogIGluc3RhbGwucGFja2FnZXMoInZpcmlkaXMiKQ0KICBsaWJyYXJ5KHZpcmlkaXMpDQp9DQppZiAoIXJlcXVpcmUoImxlYWZlbSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmVtIikNCmxpYnJhcnkoImxlYWZlbSIpDQp9DQppZiAoIXJlcXVpcmUoInNwRGF0YUxhcmdlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJzcERhdGFMYXJnZSIsIHJlcG9zID0gImh0dHBzOi8vZ2VvY29tcHIuci11bml2ZXJzZS5kZXYiKQ0KbGlicmFyeSgic3BEYXRhTGFyZ2UiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0LmV4dHJhcyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldC5leHRyYXMiKQ0KbGlicmFyeSgibGVhZmxldC5leHRyYXMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXR0aWNlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsYXR0aWNlIikNCmxpYnJhcnkoImxhdHRpY2UiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJzcCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygic3AiKQ0KbGlicmFyeSgic3AiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJwYW5kZXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJybGlzdCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicmxpc3QiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgicmxpc3QiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJEVCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiRFQiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiRFQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjcm9zc3RhbGsiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImNyb3NzdGFsayIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjcm9zc3RhbGsiKQ0KfQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgPSBUUlVFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQojIHNob290aW5nX2RhdGEgPC0gbmEub21pdChyZWFkLmNzdihmaWxlPSJodHRwczovL2dpdGh1Yi5jb20vY2hpbndleC9TVEE1NTMvcmF3L21haW4vdzA4L3Nob290aW5ncy5jc3YiKSkNCiMgcGhpbCAgPC0gbmEub21pdChzdF9yZWFkKCJodHRwczovL2dpdGh1Yi5jb20vY2hpbndleC9TVEE1NTMvcmF3L21haW4vdzA4L3Nob290aW5ncy5nZW9qc29uIikpDQpzaG9vdGluZ19kYXRhICA8LSBuYS5vbWl0KHN0X3JlYWQoImh0dHBzOi8vcGVuZ2RzY2kuZ2l0aHViLmlvL1NUQTU1M1ZJWi93MDgvUGhpbGx5U2hvb3RpbmdzLmdlb2pzb24iKSkNCnBoaWxseU5laWdoYm9yICA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L05laWdoYm9yaG9vZHNfUGhpbGFkZWxwaGlhLmdlb2pzb24iKQ0KcGhpbGx5ICA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L1BoaWxseU5laWdoYm9yaG9vZC1ibG9ja3MuZ2VvanNvbiIpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NClRoaXMgZGF0YXNldCBpcyBhIGNvbWJpbmF0aW9uIG9mIGZpZWxkcyBmcm9tIE9mZmljZXIgSW52b2x2ZWQgU2hvb3RpbmdzIChPSVMpIGRhdGEgYXMgd2VsbCBhcyBmaWVsZHMgZnJvbSBjcmltaW5hbCBzaG9vdGluZyB2aWN0aW0gZGF0YSBmcm9tIHRoZSBQaGlsYWRlbHBoaWEgUG9saWNlIERlcGFydG1lbnQuIFRoZSBzaG9vdGluZyB2aWN0aW0gaW5mb3JtYXRpb24gaXMgZW50ZXJlZCBtYW51YWxseSB0byB0aGUgc291cmNlIGRhdGFiYXNlIGJ5IGV4YW1pbmluZyBpbnZlc3RpZ2F0aXZlIHJlcG9ydHMgZnJvbSBEZXRlY3RpdmVzLg0KDQpUaGVyZSBhcmUgMTUyNzcgb2JzZXJ2YXRpb25zIGFuZCAyMiB2YXJpYWJsZXMuIFNvbWUgb2YgdGhlIHZhcmlhYmxlcyBhbmQgdGhlaXIgZGVzY3JpcHRpb25zIGluY2x1ZGU6DQoNCi0gQUdFIC0gVGhlIGFnZSBvZiB0aGUgaW5kaXZpZHVhbCB3aG8gd2FzIHNob3QuDQotIFNFWCAtIFRoZSBzZXggb2YgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90Lg0KLSBSQUNFIC0gVGhlIHJhY2Ugb2YgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90Lg0KLSBDT0RFIC0gVGhlIENyaW1lIENsYXNzaWZpY2F0aW9uIENvZGUgYmFzZWQgb2ZmIG9mIHRoZSBGQkkncyBDcmltZSBSZXBvcnRpbmcgKFVDUikgc3lzdGVtLg0KMDAwMDogQWRkaXRpb25hbCBWaWN0aW07DQowMTAwIOKAkyAwMTE5OiBIb21pY2lkZTsNCjAyMDAg4oCTIDAyOTk6IFJhcGU7DQowMzAwIOKAkyAwMzk5OiBSb2JiZXJ5Ow0KMDQwMCDigJMgMDQ5OTogQWdncmF2YXRlZCBBc3NhdWx0Ow0KMzAwMCDigJMgMzkwMDogSG9zcGl0YWwgQ2FzZXM7DQotIERBVEUgLSBUaGUgZGF0ZSBvbiB3aGljaCB0aGUgc2hvb3RpbmcgdG9vayBwbGFjZQ0KLSBEQ19LRVkgLSBUaGUgdW5pcXVlIGluY2lkZW50IGlkZW50aWZpZXIuDQotIERJU1QgLSBUaGUgZGlzdHJpY3QgaW4gd2hpY2ggdGhlIHNob290aW5nIHRvb2sgcGxhY2UuDQotIEZBVEFMIC0gV2hldGhlciB0aGUgaW5kaXZpZHVhbCBkaWVkIGFzIGEgcmVzdWx0IG9mIHRoZSBzaG9vdGluZy4gMD1ObyBhbmQgMT1ZZXMuIFRoZSDigJxGQVRBTOKAnSBjb2x1bW4gaXMgZnJvbSB0aGUgY3JpbWluYWwgc2hvb3RpbmcgdmljdGltIGRhdGEgYW5kIG9ubHkgaW5kaWNhdGVzIGlmIHNvbWVvbmUgZGllZCBmcm9tIGEgY3JpbWluYWwgc2hvb3RpbmcuDQotIElOU0lERSAtIFdoZXRoZXIgdGhlIHNob290aW5nIGluY2lkZW50IHRvb2sgcGxhY2UgaW5zaWRlIGEgYnVpbGRpbmcvaG9tZSwgd2hlcmUgMD1Obywgbm90IGluc2lkZSBhbmQgMT1ZZXMsIGluc2lkZS4NCi0gTEFUSU5PIC0gV2hldGhlciBvciBub3QgdGhlIGluZGl2aWR1YWwgd2hvIHdhcyBzaG90IHdhcyBvZiBMYXRpbm8gZXRobmljaXR5Lg0KLSBMT0NBVElPTiAtIFRoZSBsb2NhdGlvbiwgZ2VuZXJhbGl6ZWQgdG8gdGhlIGJsb2NrIGxldmVsLCBvZiB0aGUgc2hvb3RpbmcuDQotIE9GRkVOREVSX0RFQ0VBU0VEIC0gV2hldGhlciB0aGUgb2ZmZW5kZXIgZGllZCBpbiBhbiBvZmZpY2VyLWludm9sdmVkIHNob290aW5nIGluY2lkZW50IChOPU5vIGFuZCBZPVllcykuDQoNClNob3duIGJlbG93IGFyZSB0aGUgZmlyc3QgNiBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgZGF0YXNldDoNCg0KYGBge3J9DQprYWJsZShoZWFkKHNob290aW5nX2RhdGEpKQ0KYGBgDQoNCiMgT2JqZWN0aXZlcyBvZiB0aGUgSW50ZXJhY3RpdmUgUGxvdA0KVGhlIHNob290aW5nIGRhdGEgc2V0IGlzIG5laXRoZXIgYSBwb3B1bGF0aW9uIG5vciBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHBvcHVsYXRpb24gaW4gUGhpbGFkZWxwaGlhLiBJdCBpcyBhIHNldCBvZiBwdWJsaWMgcmVjb3JkcyBvZiBzaG9vdGluZ3MgaW4gdGhlIG5laWdoYm9yaG9vZHMgb2YgUGhpbGFkZWxwaGlhIGZvciB0aGUgcGFzdCAxMCB5ZWFycy4gVGhpcyBkYXRhIGNvbnRhaW5zIHNvbWUgZ2VvZ3JhcGhpY2FsIGluZm9ybWF0aW9uIHN1Y2ggYXMgZGlzdHJpY3QgaW5mb3JtYXRpb24sIGJsb2NrL2xvY2F0aW9uLCBsb25naXR1ZGUsIGxhdGl0dWRlIGV0Yy4gVGhlIG1haW4gb2JqZWN0aXZlcyBhcmU6DQoNCi0gU2hvb3RpbmcgdHJlbmQgYnkgeWVhcg0KLSBBZ2UgZGVuc2l0eSBkaXN0cmlidXRpb24NCi0gQnViYmxlIHBsb3Qgb24gdGhlIG1hcA0KLSBUYWJsZSBvZiB0b3RhbCBzaG9vdGluZ3MgY2F0ZWdvcml6ZWQgdW5kZXIgUmFjZSwgU2V4IGFuZCBBZ2UgZnJvbSAyMDE1IHQwIDIwMjQNCi0gQmFyIHBsb3Qgb2Ygc2hvb3RpbmcgY291bnRzIGJ5IFJhY2UNCi0gTWFwIHNob3dpbmcgc2hvb3RpbmcgY291bnRzIGZvciBlYWNoIGRpc3RyaWN0DQoNCiMjIFRvdGFsIFNob290aW5ncyBmb3IgRGlzdHJpY3RzDQoNClNob290aW5nIGRhdGEgd2FzIGFnZ3JlZ2F0ZWQgYnkgZGlzdHJpY3QgdG8gaW5jbHVkZSBmYXRhbCwgbm9uZmF0YWwgYW5kIHRvdGFsIHNob290aW5ncyBmb3IgYWxsIGRpc3RyaWN0cy4gVGhpcyBpbmZvcm1hdGlvbiB3YXMgaWxsdXN0cmF0ZWQgb24gYSBtYXAgYW5kIHNob3duIGJlbG93LiBUaGUgY2lyY2xlIHNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIHRoZSBudW1iZXIgb2Ygc2hvb3RpbmdzIGluIGEgZGlzdHJpY3QuIERpc3RyaWN0IDI1IGhhZCB0aGUgbGFyZ2VzdCBmYXRhbCBhbmQgbm9uZmF0YWwgc2hvb3RpbmdzLg0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgTWFwIFNob3dpbmcgVG90YWwgU2hvb3RpbmdzIGluIFBoaWxhZGVscGhpYSBEaXN0cmljdHMifQ0Kc2hvb3RpbmdfZGF0YSRsbmcgPSBzaG9vdGluZ19kYXRhJHBvaW50X3gNCnNob290aW5nX2RhdGEkbGF0ID0gc2hvb3RpbmdfZGF0YSRwb2ludF95DQoNCmRpc3QuQ3JpbWVUYWJsZSA9IHRhYmxlKHNob290aW5nX2RhdGEkZmF0YWwsIHNob290aW5nX2RhdGEkZGlzdCkNCg0KZGlzdExvbiA9IGFnZ3JlZ2F0ZShzaG9vdGluZ19kYXRhJGxuZywgYnk9bGlzdChzaG9vdGluZ19kYXRhJGRpc3QpLCBGVU49bWVhbikNCmRpc3RMYXQgPSBhZ2dyZWdhdGUoc2hvb3RpbmdfZGF0YSRsYXQsIGJ5PWxpc3Qoc2hvb3RpbmdfZGF0YSRkaXN0KSwgRlVOPW1lYW4pDQpkaXN0TG9uTGF0ID0gbWVyZ2UoZGlzdExvbiwgZGlzdExhdCwgYnkgPSAiR3JvdXAuMSIpDQpuYW1lcyhkaXN0TG9uTGF0KSA9IGMoImRpc3RyaWN0IiwgImxuZyIsICJsYXQiKQ0KDQoNCmRpc3RDcmltZSA9IGRhdGEuZnJhbWUoZGlzdHJpY3Q9YXMubnVtZXJpYyhuYW1lcyh0YWJsZShzaG9vdGluZ19kYXRhJGRpc3QpKSksIA0KICAgICAgICAgICAgICAgICAgICAgIGZhdGFsID0gdGFibGUoc2hvb3RpbmdfZGF0YSRmYXRhbCwgc2hvb3RpbmdfZGF0YSRkaXN0KVsyLF0sDQogICAgICAgICAgICAgICAgICAgICAgbm9uZmF0YWwgPSB0YWJsZShzaG9vdGluZ19kYXRhJGZhdGFsLCBzaG9vdGluZ19kYXRhJGRpc3QpWzEsXSwNCiAgICAgICAgICAgICAgICAgICAgICB0b3RhbC5jcmltZSA9IHRhYmxlKHNob290aW5nX2RhdGEkZGlzdCkgDQogICAgICAgICAgICAgICAgICAgICAgKQ0KZGlzdENyaW1lID0gZGlzdENyaW1lWywgYygiZGlzdHJpY3QiLCAiZmF0YWwiLCAibm9uZmF0YWwiLCAidG90YWwuY3JpbWUuRnJlcSIpXQ0KY29sbmFtZXMoZGlzdENyaW1lKSA9IGMoImRpc3RyaWN0IiwgImZhdGFsIiwgIm5vbmZhdGFsIiwgInRvdGFsLmNyaW1lIikNCmRpc3RDcmltZSA9IG1lcmdlKGRpc3RMb25MYXQsIGRpc3RDcmltZSwgYnkgPSAiZGlzdHJpY3QiKQ0KDQp0aXRsZTIgPC0gdGFncyRkaXYoSFRNTCgnPGZvbnQgY29sb3IgPSAiZGFya3JlZCIgc2l6ZSA9NT48Yj5TaG9vdGluZ3MgaW4gUGhpbGFkZWxwaGlhIERpc3RyaWN0czwvYj48L2ZvbnQ+JykpDQoNCnBhbDAgPC0gY29sb3JOdW1lcmljKHBhbGV0dGUgPSB2aXJpZGlzKDI1Niwgb3B0aW9uID0gIkIiKSwgZG9tYWluID0gcmFuZ2UoZGlzdENyaW1lJHRvdGFsLmNyaW1lKSkNCmRpc3RmaWcgPC0gbGVhZmxldCgpICU+JQ0KICBzZXRWaWV3KGxuZz0tNzUuMTUyNywgbGF0PTM5Ljk3MDcsIHpvb20gPSAxMSkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUgDQogICMjIHBsb3QgdGhlIG5laWdoYm9yaG9vZCBib3VuZGFyeSBvZiBQaGlsbHkNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdsaWdodGdyZWVuJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICAgYWRkQ29udHJvbCh0aXRsZTIsIHBvc2l0aW9uID0gInRvcHJpZ2h0IiwgY2xhc3NOYW1lPSJtYXAtdGl0bGUiKSU+JQ0KICAjIw0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkaXN0Q3JpbWUsDQogICAgICAgICAgICAgICAgICAgcmFkaXVzID0gfigodG90YWwuY3JpbWUpXigxLzMpKSwNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWwwKHRvdGFsLmNyaW1lKSwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+cGFzdGUoJ0Rpc3RyaWN0OicsZGlzdHJpY3QsIA0KICAgICAgICAgICAgICAgICAgICAgICc8YnI+VG90YWwgQ3JpbWU6JywgdG90YWwuY3JpbWUsIA0KICAgICAgICAgICAgICAgICAgICAgICc8YnI+RmF0YWwgQ3JpbWU6JywgZmF0YWwsDQogICAgICAgICAgICAgICAgICAgICAgJzxicj5Ob25mYXRhbCBDcmltZTonLCBub25mYXRhbCkpDQpkaXN0ZmlnDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QudGhlbWUgPC0gZnVuY3Rpb24oKSB7DQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAic2FucyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwOUU3MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNSksDQogICAgIyBhZGQgYm9yZGVyIDEpDQogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICIjMDA5RTczIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMiksDQogICAgIyBjb2xvciBiYWNrZ3JvdW5kIDIpDQogICAjIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRjBFNDQyIiksDQogICAgIyBtb2RpZnkgZ3JpZCAzKQ0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41KSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gIGVsZW1lbnRfbGluZShjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjUpLA0KICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgIA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiIzU2QjRFOSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gIml0YWxpYyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiVGltZXMgTmV3IFJvbWFuIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiIzAwNzJCMiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gIlRpbWVzIE5ldyBSb21hbiIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIiM1NkI0RTkiKSkNCn0NCmBgYA0KDQoNCiMjIFNob290aW5nIFRyZW5kIGJ5IFllYXINClRoZSBwbG90IGJlbG93IHNob3dzIHRoZSBzaG9vdGluZyB0cmVuZCBmcm9tIDIwMTUgdG8gMjAyNC4gVGhlcmUgd2FzIGEgc2hhcnAgaW5jcmVhc2UgaW4gdGhlIG51bWJlciBvZiBzaG9vdGluZ3MgZnJvbSAyMDE5IHRvIDIwMjAuIFRoaXMgaW5jcmVhc2Ugd2FzIG1haW50YWluZWQgYWxsIHRocm91Z2ggdGlsbCAyMDIyIGFuZCB0aGVuIHdhcyBmb2xsb3dlZCBieSBhIHNoYXJwIGRlY2xpbmUgaW4gMjAyMy4gVGhlIGluY3JlYXNlIHNlZW4gZnJvbSAyMDIwIHRvIDIwMjIgY2FuIGJlIHJlbGF0ZWQgdG8gdGhlIGNvcm9uYXZpcnVzIHBlcmlvZC4NCg0KYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcCA9ICJBIFRyZW5kIFBsb3Qgb2YgU2hvb3RpbmcgQ3JpbWVzIGJ5IFllYXIiLCB3YXJuaW5nPUZBTFNFfQ0KIyB0cmVuZA0KDQp5ZWFyQ3JpbWUgPSBkYXRhLmZyYW1lKHllYXI9YXMubnVtZXJpYyhuYW1lcyh0YWJsZShzaG9vdGluZ19kYXRhJHllYXIpKSksIA0KICAgICAgICAgICAgICAgICAgICAgIGZhdGFsID0gdGFibGUoc2hvb3RpbmdfZGF0YSRmYXRhbCwgc2hvb3RpbmdfZGF0YSR5ZWFyKSkNCg0KeWVhckNyaW1lID0geWVhckNyaW1lWywtMV0NCmNvbG5hbWVzKHllYXJDcmltZSkgPSBjKCJmYXRhbCIsICJ5ZWFyIiwgInRvdGFsIikNCg0KQTEgPC0gZ2dwbG90KGRhdGEgPSB5ZWFyQ3JpbWUsIGFlcyh4ID0geWVhciwgeSA9IHRvdGFsLCBncm91cCA9IGZhdGFsLCBjb2wgPSBmYXRhbCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdG90YWwpLCBzaXplID0gMykgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiNENTVFMDAiLCAiIzAwNzJCMiIpLCBsYWJlbHM9YygiTm9uZmF0YWwiLCAiRmF0YWwiKSkrDQogIHBsb3QudGhlbWUoKSsNCiAgbGFicyh0aXRsZSA9ICJTaG9vdGluZyBDb3VudHMgYnkgWWVhciIsDQogICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIlNob290aW5nIENvdW50cyIpDQpBMQ0KDQpgYGANCg0KIyMgQWdlIERpc3RyaWJ1dGlvbg0KVGhlIGRlbnNpdHkgcGxvdCBiZWxvdyBzaG93cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBhZ2VzIG9mIGluZGl2aWR1YWxzIHdobyB3ZXJlIHNob3QuIFRoZSBtb3N0IGNvbW1vbiBhZ2UgZm9yIHNob290aW5nIHZpY3RpbXMgd2FzIDI4LiANCg0KYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NSwgZmlnLmNhcCA9ICJBZ2UgRGlzdHJpYnV0aW9uIERlbnNpdHkgUGxvdCIsIHdhcm5pbmc9RkFMU0V9DQojIyAxLiBhZ2UgZGlzdHJpYnV0aW9uDQojIEJhc2ljIGRlbnNpdHkgcGxvdCBpbiBnZ3Bsb3QyDQpzaG9vdGluZ19kYXRhJGFnZSA9IGFzLm51bWVyaWMoc2hvb3RpbmdfZGF0YSRhZ2UpDQpmYXRhbEFnZSA9IGdncGxvdChkYXRhID0gc2hvb3RpbmdfZGF0YSwgYWVzKHggPSBhZ2UsIGZpbGwgPSBhcy5mYWN0b3IoZmF0YWwpKSApKw0KICAgICAgICAgICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjYpICArDQogICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0NDNzlBNyIsICIjNzJEOEZGIiksIGxhYmVscz1jKCJOb25mYXRhbCIsICJGYXRhbCIpKSsNCiAgbGFicyhmaWxsID0gIkZhdGFsIiwNCiAgICAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQWdlIikgKw0KICBwbG90LnRoZW1lKCkNCmZhdGFsQWdlDQpgYGANCiMjIFJhY2UgRGlzdHJpYnV0aW9uDQpBIGJhciBwbG90IHdhcyB1c2VkIHRvIGlsbHVzdHJhdGUgdGhlIHRvdGFsIHNob290aW5ncyBieSByYWNlLiBGb3VyIGRpZmZlcmVudCByYWNpYWwgZ3JvdXBzIHdlcmUgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGFzZXQuIFRoZXkgYXJlIEFzaWFuLCBCbGFjaywgVW5rbm93biBhbmQgV2hpdGUuIFRoZSBncm91cCB3aXRoIHRoZSBoaWdoZXN0IG51bWJlciBvZiBzaG9vdGluZyB2aWN0aW1zIHdlcmUgQmxhY2tzIHdpdGggb3ZlciAxMjAwMCByZWNvcmRzIGluIDEwIHllYXJzLg0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgQmFyIFBsb3QgU2hvd2luZyBTaG9vdGluZyBEaXN0cmlidXRpb24gYnkgUmFjZSIsIHdhcm5pbmc9RkFMU0V9DQoNCg0KQTIgPC0gZ2dwbG90KGRhdGEgPSBzaG9vdGluZ19kYXRhLCBhZXMoeCA9IHJhY2UpKSArDQogIGdlb21fYmFyKGNvbG9yID0gIiM1NkI0RTkiLCBmaWxsID0gInllbGxvdyIpKw0KICBsYWJzKHggPSAiUmFjZSIsDQogICAgICAgeSA9ICJUb3RhbCBTaG9vdGluZ3MiLA0KICAgICAgIHRpdGxlID0gIlBsb3Qgb2YgVG90YWwgU2hvb3RpbmdzIEJ5IFJhY2UiKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkEiID0gIkFzaWFuIiwgIkIiID0gIkJsYWNrIiwgIlUiID0gIlVua25vd24iLCAiVyIgPSAiV2hpdGUiKSkgKw0KICBwbG90LnRoZW1lKCkNCkEyDQpgYGANCg0KIyMgU3VtbWFyeSBUYWJsZQ0KQSB0YWJsZSBzdW1tYXJpemluZyB0b3RhbCBzaG9vdGluZ3MgYnkgc2V4LCByYWNlLCBhZ2UgaXMgc2hvd24gYmVsb3cuIFRoZSBhdmVyYWdlIGFnZSBvZiBzaG9vdGluZyB2aWN0aW1zIHdhcyAyOCBpbiB0aGUgZWFybGllciB5ZWFycyBhbmQgdGhlbiBpbmNyZWFzZWQgdG8gMzEgbGF0ZXIuIEJsYWNrIG1hbGVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSB2aWN0aW1zIG9mIHNob290aW5nIGNyaW1lcyB0aGFuIG90aGVyIGdyb3Vwcy4NCg0KYGBge3J9DQpkdCA9IGRhdGEuZnJhbWUoeWVhcj1hcy5udW1lcmljKG5hbWVzKHRhYmxlKHNob290aW5nX2RhdGEkeWVhcikpKSwgDQogICAgICAgICAgICAgICAgICAgICAgZmF0YWwgPSB0YWJsZShzaG9vdGluZ19kYXRhJGZhdGFsLCBzaG9vdGluZ19kYXRhJHllYXIpWzIsXSwNCiAgICAgICAgICAgICAgICAgICAgICBub25mYXRhbCA9IHRhYmxlKHNob290aW5nX2RhdGEkZmF0YWwsIHNob290aW5nX2RhdGEkeWVhcilbMSxdLA0KICAgICAgICAgICAgICAgICAgICAgIHRvdGFsLmNyaW1lID0gdGFibGUoc2hvb3RpbmdfZGF0YSR5ZWFyKSwNCiAgICAgICAgICAgICAgICAgQmxhY2sgPSB0YWJsZShzaG9vdGluZ19kYXRhJHJhY2UsIHNob290aW5nX2RhdGEkeWVhcilbMixdLA0KICAgICAgICAgICAgICAgIE1hbGVzID0gdGFibGUoc2hvb3RpbmdfZGF0YSRzZXgsIHNob290aW5nX2RhdGEkeWVhcilbMixdLA0KICAgICAgICAgICAgICAgIEZlbWFsZXMgPSB0YWJsZShzaG9vdGluZ19kYXRhJHNleCwgc2hvb3RpbmdfZGF0YSR5ZWFyKVsxLF0sDQogICAgICAgICAgICAgICAgYWdlID0gc2lnbmlmKHRhcHBseShzaG9vdGluZ19kYXRhJGFnZSwgc2hvb3RpbmdfZGF0YSR5ZWFyLCBtZWFuKSwgZGlnaXRzID0gMikNCiAgICAgICAgICAgICAgICAgICAgICApDQpkdCA9IGR0WywtYygxLDQsNSldDQpjb2xuYW1lcyhkdCkgPSBjKCJGYXRhbCIsICJOb25mYXRhbCIsICJCbGFjayIsICJNYWxlcyIsICJGZW1hbGVzIiwgIkFnZSIpDQpBMyA8LSBEVDo6ZGF0YXRhYmxlKGR0LCBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCkEzDQoNCmBgYA0KDQojIyBBbmltYXRlZCBQbG90IG9mIFNob290aW5ncyBCeSBZZWFyDQoNCmBgYHtyIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXAgPSAiQW5pbWF0ZWQgcGxvdCBvZiBQaGlsYWRlbHBoaWEgU2hvb3RpbmdzIEJ5IFllYXIifQ0Kd2hpY2hfc3RhdGUgPC0gInBlbm5zeWx2YW5pYSINCmNvdW50eV9pbmZvIDwtIG1hcF9kYXRhKCJjb3VudHkiLCByZWdpb249d2hpY2hfc3RhdGUpDQpwaGlsbHlfaW5mbyA8LSBjb3VudHlfaW5mb1tjb3VudHlfaW5mbyRzdWJyZWdpb24gPT0gInBoaWxhZGVscGhpYSIsXQ0KDQoNCmJhc2VfbWFwIDwtIGdncGxvdChkYXRhID0gcGhpbGx5X2luZm8sIG1hcHBpbmcgPSBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApKSArDQogZ2VvbV9wb2x5Z29uKGNvbG9yID0gIiMwMDlFNzMiLCBmaWxsID0gImxpZ2h0eWVsbG93IikgKw0KICBjb29yZF9xdWlja21hcCgpICsNCiAgdGhlbWVfdm9pZCgpIA0KDQptYXBfd2l0aF9kYXRhIDwtIGJhc2VfbWFwICsNCiAgZ2VvbV9wb2ludChkYXRhID0gc2hvb3RpbmdfZGF0YSwgYWVzKHggPSBsbmcsIHkgPSBsYXQsIGNvbG9yID0gZmFjdG9yKGZhdGFsKSwgZmlsbCA9IGZhY3RvcihmYXRhbCksIGdyb3VwPXllYXIpLCBzaXplID0gMiwgYWxwaGEgPSAwLjUpICArDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIxLCAyNCkpICsNCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDA3MkIyIiwgIiNENTVFMDAiKSkNCg0KbWFwX3dpdGhfYW5pbWF0aW9uIDwtIG1hcF93aXRoX2RhdGEgKw0KICB0cmFuc2l0aW9uX3RpbWUoeWVhcikgKw0KICBnZ3RpdGxlKCdZZWFyOiB7ZnJhbWVfdGltZX0nKSArDQogICBzaGFkb3dfbWFyaygpDQoNCmFuaW1fc2F2ZSgiU2hvb3RpbmdzQnlZZWFyLmdpZiIsIG1hcF93aXRoX2FuaW1hdGlvbikNCm1hcF93aXRoX2FuaW1hdGlvbg0KDQpgYGANCg0KDQoNCiMgSW50ZXJhY3RpdmUgTWFwIG9mIFBoaWxhZGVscGhpYSBTaG9vdGluZ3MNCg0KQSBtYXAgdmlzdWFsaXppbmcgYWxsIHRoZSByZWxldmFudCBpbmZvcm1hdGlvbiBhbmQga2V5IHBvaW50cyBkZW1vbnN0cmF0ZWQgYWJvdmUgaXMgc2hvd24gYmVsb3cuIA0KDQpgYGB7ciBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkEgTWFwIG9mIFBoaWxhZGVscGhpYSBTaG9vdGluZ3MifQ0KDQpnaWYgPSBzdF9hc19zZihkYXRhLmZyYW1lKHggPSAtNzUuNDA3NywgeSA9IDM5LjkxNjgpLA0KICAgICAgICAgICAgICAgIGNvb3JkcyA9IGMoIngiLCAieSIpLA0KICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpDQp0bmQgPSBzdF9hc19zZihkYXRhLmZyYW1lKHggPSAtNzUuMzg3NywgeSA9IDM5LjkxNjgpLA0KICAgICAgICAgICAgICAgIGNvb3JkcyA9IGMoIngiLCAieSIpLA0KICAgICAgICAgICAgICAgIGNycyA9IDQzMjYpDQphZ2VEaXN0ID0gc3RfYXNfc2YoZGF0YS5mcmFtZSh4ID0gLTc1LjM2NzcsIHkgPSAzOS45MTY4KSwNCiAgICAgICAgICAgICAgICBjb29yZHMgPSBjKCJ4IiwgInkiKSwNCiAgICAgICAgICAgICAgICBjcnMgPSA0MzI2KQ0KZGlzdGxvYyA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zNDc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCnRibCA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zMjc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCmJwbCA9IHN0X2FzX3NmKGRhdGEuZnJhbWUoeCA9IC03NS4zMDc3LCB5ID0gMzkuOTE2OCksDQogICAgICAgICAgICAgICAgY29vcmRzID0gYygieCIsICJ5IiksDQogICAgICAgICAgICAgICAgY3JzID0gNDMyNikNCg0KdGl0bGUxIDwtIHRhZ3MkZGl2KEhUTUwoJzxmb250IGNvbG9yID0gImRhcmtyZWQiIHNpemUgPTU+PGI+U2hvb3RpbmdzIGluIFBoaWxhZGVscGhpYTwvYj48L2ZvbnQ+JykpDQoNCmZsID0gdGVtcGZpbGUoZmlsZWV4dCA9ICIuaHRtbCIpDQpzYXZlV2lkZ2V0KGRpc3RmaWcsIGZpbGUgPSBmbCkNCg0KDQpwaGlsY29sb3IgPC0gcmVwKCIjMDA3MkIyIiwgbGVuZ3RoKHNob290aW5nX2RhdGEkZmF0YWwpKQ0KcGhpbGNvbG9yW3doaWNoKHNob290aW5nX2RhdGEkZmF0YWwgPT0gMSldIDwtICIjRDU1RTAwIg0KDQpzaG9vdGluZ2J5eWVhciA8LSAiaHR0cHM6Ly9naXRodWIuY29tL2NoaW53ZXgvU1RBNTUzL3Jhdy9tYWluL3cwOC9TaG9vdGluZ3NCeVllYXIuZ2lmIg0KDQpsYWJlbHMgPC0gIHBhc3RlKCJMb2NhdGlvbjogIixzaG9vdGluZ19kYXRhJGxvY2F0aW9uLCANCiAgICAgICAgICAgICAiPGJyPldvdW5kOiAiLCBzaG9vdGluZ19kYXRhJHdvdW5kLA0KICAgICAgICAgICAgICAiPGJyPlNleDogIiwgc2hvb3RpbmdfZGF0YSRzZXgsDQogICAgICAgICAgICAgIjxicj5ZZWFyOiAiLCBzaG9vdGluZ19kYXRhJHllYXIsDQogICAgICAgICAgICAgIjxicj5BZ2U6ICIsIHNob290aW5nX2RhdGEkYWdlKSU+JSANCiAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KDQoNCmxlYWZsZXQoKSAlPiUNCiAgc2V0Vmlldyhsbmc9LTc1LjE1MDkyLCBsYXQ9NDAuMDA5OTUsIHpvb20gPSAxMSkgJT4lDQogICNhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRFc3JpLldvcmxkR3JheUNhbnZhcywgZ3JvdXAgPSAiR3JleSIpJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuRGFya01hdHRlciwgZ3JvdXA9IkRhcmsiKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5EYXJrTWF0dGVyTm9MYWJlbHMsIGdyb3VwPSJEYXJrTGFiZWwiKSAlPiUgIA0KIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuTmF0R2VvV29ybGRNYXAsIGdyb3VwPSJFc3JpIikgJT4lDQogIA0KICBhZGRDb250cm9sKHRpdGxlMSwgcG9zaXRpb24gPSAidG9wcmlnaHQiLCBjbGFzc05hbWU9Im1hcC10aXRsZSIpICU+JQ0KICAjIyBtaW5pIHJlZmVyZW5jZSBtYXANCiAgYWRkTWluaU1hcCgpICU+JQ0KICAjIyBuZWlnaGJvcmhvb2QgYm91bmRhcnkNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdsaWdodGdyZWVuJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICAjIyBwbG90IGluZm9ybWF0aW9uIG9uIHRoZSBtYXANCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gc2hvb3RpbmdfZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgIH5sbmcsIA0KICAgICAgICAgICAgICAgICAgICAgfmxhdCwNCiAgICAgICAgICAgIGNvbG9yID0gcGhpbGNvbG9yLA0KICAgICAgICAgICAgZmlsbENvbG9yID0gaWZlbHNlKHNob290aW5nX2RhdGEkZmF0YWwgPT0gMSwgIiNmZmZmNjYiLCAiI2ZmOTlmZiIpLA0KICAgICAgICAgICAgcmFkaXVzID0gMTAsDQogICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgIyBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC4yNSwNCiAgICAgICAgICAgIGxhYmVsID0gfmxhYmVscywNCiAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMobWF4Q2x1c3RlclJhZGl1cyA9IDQwKSkgJT4lDQogIA0KICAjIFRyZW5kIG9mIGNyaW1lcyBvdmVyIHRoZSB5ZWFycw0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSB0bmQsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJUcmVuZCIsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC45NSwNCiAgICAgICAgICAgICAgICAgICBncm91cCA9ICJ0bmQiKSAlPiUNCiAgYWRkUG9wdXBHcmFwaHMobGlzdChBMSksIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJ0bmQiKSAlPiUNCiAjIGFnZSBkaXN0cmlidXRpb24gd2l0aGluIHRoZSB0d28gdHlwZXMgb2YgY3JpbWVzDQogYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gYWdlRGlzdCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwNzJCMiIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJBZ2UgRGlzdHJpYnV0aW9uIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImFnZURpc3QiKSAlPiUNCiAgYWRkUG9wdXBHcmFwaHMobGlzdChmYXRhbEFnZSksIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJhZ2VEaXN0IikgJT4lDQogICMgc2hvb3RpbmcgY291bnRzIGJ5IGRpc3RyaWN0OiBidWJibGUgcGxvdA0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkaXN0bG9jLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJwdXJwbGUiLA0KICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IDIsDQogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAiQ3JpbWVzIGJ5IERpc3RyaWN0IiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImRpc3Rsb2MiKSAlPiUNCiAgbGVhZnBvcDo6OmFkZFBvcHVwSWZyYW1lcygNCiAgICAgICAgICAgICAgICAgIHNvdXJjZSA9IGZsLA0KICAgICAgICAgICAgICAgICAgIHdpZHRoID0gNDUwLA0KICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMzAwLA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImRpc3Rsb2MiKSAlPiUNCiAgIyBBbmltYXRlZCBzaG9vdGluZyBjb3VudHMgYnkgeWVhcnMNCiAgIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGdpZiwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiI0NDNzlBNyIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJTaG9vdGluZ3MgYnkgeWVhciIsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC45NSwNCiAgICAgICAgICAgICAgICAgICBncm91cCA9ICJnaWYiKSAlPiUNCiAgYWRkUG9wdXBJbWFnZXMoc2hvb3RpbmdieXllYXIsIA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSA0NTAsDQogICAgICAgICAgICAgICAgICBoZWlnaHQgPSAzMDAsDQogICAgICAgICAgICAgICAgICB0b29sdGlwID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBncm91cCA9ICJnaWYiKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHRibCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ29sZCIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJTdW1tYXJ5IFRhYmxlIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gInRibCIsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSBodG1sVGFibGUoZHQpKSAlPiUNCiAgIyBiYXJwbG90IG9mIGNyaW1lIGJ5IHJhY2UNCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gYnBsLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJncmVlbiIsDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwNCiAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJDcmltZSBieSBSYWNlIiwNCiAgICAgICAgICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjk1LA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gImJwbCIpICU+JQ0KICBhZGRQb3B1cEdyYXBocyhsaXN0KEEyKSwgDQogICAgICAgICAgICAgICAgICB3aWR0aCA9IDQ1MCwNCiAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDMwMCwNCiAgICAgICAgICAgICAgICAgIHRvb2x0aXAgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgIGdyb3VwID0gImJwbCIpICU+JQ0KICBhZGRMYXllcnNDb250cm9sKGJhc2VHcm91cHMgPSBjKCdEYXJrJywgJ0RhcmtMYWJlbCcsICdFc3JpJyksDQogICAgICAgICAgICAgICAgICAgb3ZlcmxheUdyb3VwcyA9IGMoIlNob290aW5nIERhdGEiKSwNCiAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gVFJVRSkpICU+JQ0KICAjIw0KICBicm93c2FibGUoKQ0KDQpgYGANCg0KDQoNCg0K